<template>
  <div class="target-correlation-analysis">
    <div class="search">
      <div class="my-form">
        <el-config-provider :locale="zhCn">
          <el-date-picker
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期">
          </el-date-picker>        
        </el-config-provider>
      </div>
      <el-button type="primary" :icon="Search">搜索</el-button>
    </div>

    <div class="chart">
      <div id="my-relationship-chart"></div>
    </div>

    <div class="container">
      <el-table
        height="100%"
        :header-cell-style="elTableStyle.headerCellStyle"
        border
        :data="state.tableData">
        <el-table-column
          :width="item.width"
          :show-overflow-tooltip="item.tip"
          v-for="item of state.tableHeader"
          :label="item.label"
          :prop="item.prop"
          align="center"
          :key="item.prop">
        </el-table-column>
      </el-table>

      <el-config-provider :locale="customPagination">
        <el-pagination
          background
          @current-change="handleCurrentChange"
          v-model:current-page="state.currentPage"
          :page-size="6"
          layout="total, prev, pager, next, jumper"
          :total="state.total">
        </el-pagination>      
      </el-config-provider>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { Search } from "@element-plus/icons-vue";
import customPagination from "../../../config/third-plugins/customPagination";
import zhCn from "element-plus/lib/locale/lang/zh-cn";

import * as echarts from "echarts";

import cm from "../../../assets/img/node1.png";
import elTableStyle from "../../../config/third-plugins/element/elTable";

interface tca {
  chartOption:any,

  currentPage:number,
  total:number,
  tableData:Array<any>,
  tableHeader:Array<any>
}

const state = reactive<tca>({
  chartOption: {},

  currentPage: 1,
  total: 0,
  tableData: [],
  tableHeader: [
    { label: '源地址', prop: 'origin', tip: true, width: '200' },
    { label: '源端口', prop: 'src_port', tip: true, width: '200' },
    { label: '目标地址', prop: 'target', tip: true, width: '200' },
    { label: '目标端口', prop: 'dst_port', tip: true, width: '200' },
    { label: '信息描述', prop: 'desc', tip: true }
  ]
})

const darw = () => {
  let nodes = state.tableData.map((i:any) => {
    return [
      {
        symbol: 'image://' + cm,
        symbolSize: 30,
        name: i.origin
      },
      {
        symbol: 'image://' + cm,
        symbolSize: 30,
        name: i.target
      }
    ]
  })

  nodes = uniqueJSON(nodes.flat(), 'name')

  const links = state.tableData.map(i => {
    return {
      source: i.origin,
      target: i.target,
      value: '1'
    }
  })

  state.chartOption = {
    series: [
      {
        type: "graph",
        layout: "force",
        roam: true,
        label: {
          show: true,
          align: 'center',
          textStyle: { fontSize: 12, color: '#333' }, 
          position: 'bottom',
          formatter: (params:any) => {
            return `{a|${params.name}}`
          },
          rich: {
            a: {
              color: '#fff',
              padding: [4, 5],
              backgroundColor: 'rgba(64, 158, 255, 1)'
            }
          }
        },
        draggable: true, // 节点是否可拖拽，只在使用力引导布局的时候有用。
        focusNodeAdjacency: true, // 是否在鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点。

        force: {
          repulsion: 150, // 节点之间的斥力因子。支持数组表达斥力范围，值越大斥力越大。
          gravity: 0.05, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
          edgeLength: 100, // 边的两个节点之间的距离，这个距离也会受 repulsion影响 。值越大则长度越长
          layoutAnimation: true // 因为力引导布局会在多次迭代后才会稳定，这个参数决定是否显示布局的迭代动画
          // 在浏览器端节点数据较多（>100）的时候不建议关闭，布局过程会造成浏览器假死。
        },

        edgeSymbol: ["", "arrow"],
        edgeLabel: {
          show: false,
          align: 'center',
          position: 'middle',
          textStyle: { fontSize: 18, color: '#333' },
          formatter: (params:any) => {
            return `{a|${params.value}}`
          },
          rich: {
            a: {
              color: '#fff',
              width: 20,
              height: 20,
              backgroundColor: 'rgba(72, 162, 255, 1)',
              borderRadius: 100,
              opacity: 0.8,
              lineHeight: 0,
              fontSize: 10
            }
          }
        },

        links: links,
        lineStyle: {
          normal: {
            color: '#3c3c3c',
            opacity: 1,
            width: 1,
            curveness: 0
          }
        },

        data: nodes,
        itemStyle: {
          normal: {
            width: 100,
            height: 100,
            backgroundColor: 'red'
          }
        }
      }
    ]
  }

  const dom = document.getElementById('my-relationship-chart')
  const mychart = echarts.init(dom as HTMLElement)

  mychart.clear()
  mychart.setOption(state.chartOption)

  window.addEventListener('resize', () => {
    nextTick(() => {
      const dom = document.getElementById('my-relationship-chart')
      if (dom) {
        mychart.resize()
      }
    })
  })
}

// json 数据去重
const uniqueJSON = (arr:any, attrName:any) => {
  let result = arr.filter((item:any, index:any, self:any) => {
    return index === self.findIndex((t:any) => (t[attrName] === item[attrName]))
  })
  return result
}

const init = () => {
  $ajax.get('nnlinks', {
    'pagination[pageSize]': 6,
    'pagination[page]': state.currentPage,
    populate: '*'
  }).then(res => {
    const { data, meta } = res
    state.total = meta.pagination.total
    state.tableData = data.map((i:any) => {
      return {
        origin: i.attributes.node1.data.attributes.ip, // 源IP
        target: i.attributes.node2.data.attributes.ip,
        src_port: !i.attributes.flow ? '-' : i.attributes.flow.data.attributes.srcport, // 源端口
        dst_port: !i.attributes.flow ? '-' : i.attributes.flow.data.attributes.dstport, // 目标端口
        desc: i.attributes.desc // 描述
      }
    })
    darw()
  })
}

const handleCurrentChange = (val:any) => {
  state.currentPage = val
  init()
}

onMounted(() => {
  init()
})
</script>

<style scoped lang="scss">
.target-correlation-analysis {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  .chart {
    height: 60%;
    margin-bottom: 10px;
    div {
      height: 100%;
    }
  }
  .container {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    .el-icon-more::before {
      position: absolute;
      right: -4px;
      top: 12px;
      z-index: 9999;
      transform: rotate(90deg);
      color: #409eff;
      cursor: pointer;
      background-color: #fff;
    }
  }
  .search {
    display: flex;
    justify-content: space-between;
    .my-form {
      display: flex;
      width: 33.3%;
      justify-content: space-between;
    }
    .el-button {
      margin-left: 10px;
    }
  }

  :deep(.el-pagination) {
    align-self: end;
    margin: 15px 0;
  }

  :deep(.el-table th.el-table__cell) {
    .cell {
      border-right: 1px solid #ccc;
    }
  }
  :deep(.el-table th.el-table__cell:nth-last-child(1)) {
    .cell {
      border-right: none;
    }
  }
  :deep(.el-table--border) {
    border: none;
  }
  :deep(.el-table--border .el-table__cell) {
    border: none;
    border-bottom: 1px solid #ebeef5;
  }
  :deep(.el-table--border::after) {
    background-color: #fff;
  }

  :deep(.el-table__border-left-patch) {
    background-color: #fff;
  }
}
</style>